///*
// * refmylist.c
// *
// *  Created on: Dec 18, 2014
// *      Author: Uzi
// */
//#include "nodelock.h"
//#include "mylist.h"
//#include <stdlib.h>
//#include <stdbool.h>
//#include <stdio.h>              //TODO - remove this include before submission
//
//#define NULL_CHECK(p) if (p == NULL)
//
//struct linked_list_t
//{
//        int index;
//        void* data;
//        struct linked_list_t *next;
//        struct linked_list_t *prev;
//
//        node_lock_t prev_lock;
//        node_lock_t data_lock;
//        node_lock_t next_lock;
//};
//
//#define SUCCESS                 0
//#define NULL_ARGUMENT   1
//#define MALLOC_FAILED   2
//#define NOT_FOUND               3
//#define ALREADY_EXISTS  4
//#define NODE_LOCK_FAIL  5
//
///************************************************************************/
//linked_list_t** list_alloc()
//{
//        linked_list_t** newList = (linked_list_t**)malloc(sizeof(linked_list_t*));
//        NULL_CHECK(newList)
//        {
//                return NULL;
//        }
//        *newList = (linked_list_t*)malloc(sizeof(linked_list_t));
//        NULL_CHECK(newList)
//        {
//                free(newList);
//                return NULL;
//        }
//        (**newList).data = NULL;
//        (**newList).next = NULL;
//        (**newList).prev = NULL;
//        // The dummy's index is used as a counter for the number of nodes in the list
//        (**newList).index = 0;
//        int result = node_lock_init(&((**newList).prev_lock));
//        if (result != 0)
//        {
//                return NULL;
//        }
//        result = node_lock_init(&((**newList).data_lock));
//        if (result != 0)
//        {
//                return NULL;
//        }
//        result = node_lock_init(&((**newList).next_lock));
//        if (result != 0)
//        {
//                return NULL;
//        }
//        return newList;
//}
///************************************************************************/
//void list_free(linked_list_t** list)
//{
//        linked_list_t* current;
//        linked_list_t* prev;
//        linked_list_t* pointerToDummy;
//        NULL_CHECK(list)
//        {
//                return;
//        }
//        NULL_CHECK(*list)
//        {
//                return;
//        }
//
//        pointerToDummy = (*list);
//        *list = NULL;
//
//        /* Lock all the list for writing */
//        current = pointerToDummy;
//        do
//        {
//                write_lock(&(current->prev_lock));
//                write_lock(&(current->data_lock));
//                write_lock(&(current->next_lock));
//                prev = current;
//                current = current->next;
//        } while (current != NULL);
//
//        /* Free all the nodes from end to start */
//        do
//        {
//                current = prev;
//                prev = current->prev;
//                write_unlock(&(current->next_lock));
//                node_lock_destroy(&(current->next_lock));
//
//                write_unlock(&(current->data_lock));
//                node_lock_destroy(&(current->data_lock));
//
//                write_unlock(&(current->prev_lock));
//                node_lock_destroy(&(current->prev_lock));
//
//                free(current);
//        } while (prev != NULL);
//
//        free(list);
//}
//
///***************************************************************/
//int list_size(linked_list_t** list)
//{
//        NULL_CHECK(list){
//                return NULL_ARGUMENT;
//        }
//        NULL_CHECK(*list){                                              //check with uri delete if ont need
//                return NULL_ARGUMENT;
//        }
//        linked_list_t * headDemi = *list;               //getting the pointer to the demi node
//
//        int counter = 0 ;
//        read_lock(&(headDemi->next_lock));              //lock demi node ;
//        linked_list_t * current = headDemi->next;//getting the first node in the list
//
//        while(current){                                                 //while current is not null
//                ++counter;
//
//                read_lock(&(current->next_lock));       //lock the current node to reading and writing
//                linked_list_t * next = current->next;//get the next node from the current node
//                read_unlock(&(current->next_lock));     //unlock the current node to reading and writing
//
//                current = next;
//        }
//
//        read_unlock(&(headDemi->next_lock));    //unlock demi node
//        return counter;
//}
//
///***************************************************************/
//int list_contains(linked_list_t** list, int index)
//{
//        NULL_CHECK(list){
//                return 0;
//        }
//        NULL_CHECK(*list){
//                return 0;
//        }
//
//        linked_list_t *currentNode = *list;
//        linked_list_t *nextNode;
//
//        int pending = 1;
//        int found = 0;
//        read_lock(&(currentNode->next_lock));
//
//        while (pending) {
//                nextNode = currentNode->next;
//
//                NULL_CHECK(nextNode) {                                          //if we reached the end of the list
//                        read_unlock(&(currentNode->next_lock));
//                        return 0;
//                }
//
//                read_lock(&(nextNode->data_lock));                      // We need to access the index, so lock the data lock
//                read_unlock(&(currentNode->next_lock));         // And release the older lock
//                if (nextNode->index == index) {                         // found the desired index
//                        pending = 0;                                                    // stop looping
//                        found = 1;
//                }
//                else if (nextNode->index < index) {                     //keep searching in the list
//                        read_lock(&(nextNode->next_lock));              // start the next iteration with the "next" lock locked
//                        read_unlock(&(nextNode->data_lock));    // now can unlock the data lock
//                        currentNode = nextNode;                                 // and continue iterating
//                }
//                else {                                                                          // reached a bigger index, there's no point in searching anymore
//                        pending = 0;                                                    // stop looping
//                        found = 0;
//                }
//        }
//        read_unlock(&(nextNode->data_lock));
//        return found;
//}
///*************************************************************/
//
//int list_update_node(linked_list_t** list, int index, void* data)
//{
//        NULL_CHECK(list) {
//                return NULL_ARGUMENT;
//        }
//        NULL_CHECK(*list) {
//                return NULL_ARGUMENT;
//        }
//        linked_list_t *currentNode = *list;
//        linked_list_t *nextNode;
//
//        int result = -1;
//        int pending = 1;
//        read_lock(&(currentNode->next_lock));
//
//        while (pending) {
//                nextNode = currentNode->next;
//
//                NULL_CHECK(nextNode) {                                  //if we reached the end of the list
//                        read_unlock(&(currentNode->next_lock));
//                        return NOT_FOUND;
//                }
//
//                read_lock(&(nextNode->data_lock));
//                if (nextNode->index == index) {                 // found the desired index
//                        read_unlock(&(nextNode->data_lock));    // release the read lock (it's ok, we still have the previous "next" lock)
//                        write_lock(&(nextNode->data_lock));             // re-lock the data, but this time for writing
//                        nextNode->data = data;                                  // change the data
//                        write_unlock(&(nextNode->data_lock));   // unlock the data
//                        pending = 0;
//                        result = SUCCESS;
//                }
//                else if (nextNode->index < index) {                             // should continue searching
//                        read_unlock(&(currentNode->next_lock));
//                        read_lock(&(nextNode->next_lock));
//                        read_unlock(&(nextNode->data_lock));
//                        currentNode = nextNode;
//                }
//                else {                                                                  // reached a bigger index, there's no point in searching anymore
//                        read_unlock(&(nextNode->data_lock));
//                        result = NOT_FOUND;
//                        pending = 0;
//                }
//        }
//        read_unlock(&(currentNode->next_lock));
//        return result;
//}
//
///************************************************************************/
//int list_insert(linked_list_t** list, int index, void* data) {
//        NULL_CHECK(list) {
//                return NULL_ARGUMENT;
//        }
//        NULL_CHECK(*list) {
//                return NULL_ARGUMENT;
//        }
//
//        linked_list_t *node = malloc(sizeof(**list));
//        NULL_CHECK(node)
//        {
//                return MALLOC_FAILED;
//        }
//
//        node->index = index;
//        node->data = data;
//        node->next = NULL;
//        node->prev = NULL;
//        int result = node_lock_init(&(node->prev_lock));
//        if (result != 0)
//        {
//                free(node);
//                return NODE_LOCK_FAIL;
//        }
//        result = node_lock_init(&(node->data_lock));
//        if (result != 0)
//        {
//                node_lock_destroy(&(node->prev_lock));
//                free(node);
//                return NODE_LOCK_FAIL;
//        }
//        result = node_lock_init(&(node->next_lock));
//        if (result != 0)
//        {
//                node_lock_destroy(&(node->prev_lock));
//                node_lock_destroy(&(node->data_lock));
//                free(node);
//                return NODE_LOCK_FAIL;
//        }
//
//        write_lock(&(node->prev_lock));                                 // lock the new node for writing, so nobody else will change it while inserting
//
//        linked_list_t *currentNode = *list;
//        linked_list_t *nextNode;
//
//        result = -1;
//        int pending = 1;
//        write_lock(&(currentNode->next_lock));
//        while (pending) {
//                nextNode = currentNode->next;
//
//                NULL_CHECK(nextNode) {                          //if we reached the end of the list
//                        currentNode->next = node;
//                        node->prev = currentNode;
//                        write_unlock(&(node->prev_lock));
//                        pending = 0;
//                        result = SUCCESS;
//                        continue;
//                }
//
//                read_lock(&(nextNode->data_lock));
//                if (nextNode->index == index) {                                 //The desired index already exists
//                        read_unlock(&(nextNode->data_lock));
//                        write_unlock(&(node->prev_lock));
//                        node_lock_destroy(&(node->prev_lock));
//                        node_lock_destroy(&(node->data_lock));
//                        node_lock_destroy(&(node->next_lock));
//                        free(node);
//                        result = ALREADY_EXISTS;
//                        pending = 0;
//                        continue;
//                }
//                else if (nextNode->index < index) {                             // continue searching
//                        read_unlock(&(nextNode->data_lock));
//                        write_lock(&(nextNode->next_lock));
//                        write_unlock(&(currentNode->next_lock));
//                        currentNode = nextNode;
//                }
//                else {                                                                                  // need to insert here, between current and next
//                        read_unlock(&(nextNode->data_lock));
//                        write_lock(&(nextNode->prev_lock));
//                        currentNode->next = node;
//                        nextNode->prev = node;
//                        node->next = nextNode;
//                        node->prev = currentNode;
//                        write_unlock(&(nextNode->prev_lock));
//                        write_unlock(&(node->prev_lock));
//                        result = SUCCESS;
//                        pending = 0;
//                }
//        }
//        write_unlock(&(currentNode->next_lock));
//        return result;
//}
//
///************************************************************************/
//int list_remove(linked_list_t** list, int index) {
//        NULL_CHECK(list) {
//                return NULL_ARGUMENT;
//        }
//        NULL_CHECK(*list) {
//                return NULL_ARGUMENT;
//        }
//
//        linked_list_t *currentNode = *list;
//        linked_list_t *nextNode;
//
//        int result = -1;
//        int pending = 1;
//        write_lock(&(currentNode->next_lock));
//        while (pending) {
//                nextNode = currentNode->next;
//
//                NULL_CHECK(nextNode) {          //if we reached the end of the list
//                        pending = 0;
//                        result = NOT_FOUND;
//                        continue;
//                }
//
//                write_lock(&(nextNode->data_lock));
//                if (nextNode->index == index) {                                 //The desired index was found
//                        write_lock(&(nextNode->next_lock));
//                        linked_list_t *newNextNode = nextNode->next;
//                        NULL_CHECK(newNextNode) {                                       //If the node is at the end of the list
//                                currentNode->next = NULL;
//                        }
//                        else {                                                                          //Otherwise, the desired index is in the middle of the list
//                                write_lock(&(newNextNode->prev_lock));
//                                currentNode->next = newNextNode;
//                                newNextNode->prev = currentNode;
//                                write_unlock(&(newNextNode->prev_lock));
//
//                        }
//                        write_unlock(&(nextNode->data_lock));
//                        write_unlock(&(nextNode->next_lock));
//                        node_lock_destroy(&(nextNode->prev_lock));
//                        node_lock_destroy(&(nextNode->data_lock));
//                        node_lock_destroy(&(nextNode->next_lock));
//                        free(nextNode);
//                        pending = 0;
//                        result = SUCCESS;
//                        continue;
//                }
//                else if (nextNode->index < index) {                             // continue searching
//                        write_lock(&(nextNode->next_lock));
//                        write_unlock(&(nextNode->data_lock));
//                        write_unlock(&(currentNode->next_lock));
//                        currentNode = nextNode;
//                }
//                else {                                                                                  //The desired index doesn't exist
//                        write_unlock(&(nextNode->data_lock));
//                        result = NOT_FOUND;
//                        pending = 0;
//                }
//        }
//
//        write_unlock(&(currentNode->next_lock));
//        return result;
//}
//
///************************************************************************/
//int list_node_compute(linked_list_t** list, int index, void *(*compute_func) (void *), void** result)
//{
//        if(!list || !(*list) || !compute_func || !result) {
//                return NULL_ARGUMENT;
//        }
//
//        linked_list_t *currentNode = *list;
//        linked_list_t *nextNode;
//
//        int returnResult = -1;
//        int pending = 1;
//
//        read_lock(&(currentNode->next_lock));
//        while (pending) {
//                nextNode = currentNode->next;
//
//                NULL_CHECK(nextNode) {          //if we reached the end of the list
//                        pending = 0;
//                        returnResult = NOT_FOUND;
//                        continue;
//                }
//
//                read_lock(&(nextNode->data_lock));
//                if (nextNode->index == index) {                                 // found the desired index
//                        read_unlock(&(nextNode->data_lock));            // unlock reading (it's ok, we still have the previous lock held for reading)
//                        write_lock(&(nextNode->data_lock));                     // lock it for writing
//                        *result = compute_func(nextNode->data);         // perform the computation
//                        write_unlock(&(nextNode->data_lock));
//                        pending = 0;
//                        returnResult = SUCCESS;
//                }
//                else if (nextNode->index < index) {                             // continue searching
//                        read_unlock(&(currentNode->next_lock));
//                        read_lock(&(nextNode->next_lock));
//                        read_unlock(&(nextNode->data_lock));
//                        currentNode = nextNode;
//                }
//                else {                                          // reached a bigger index, there's no point in searching anymore
//                        read_unlock(&(nextNode->data_lock));
//                        pending = 0;
//                        returnResult = NOT_FOUND;
//                }
//        }
//        read_unlock(&(currentNode->next_lock));
//        return returnResult;
//}
//
///************************************************************************/
//typedef struct
//{
//        struct op_t *operations;
//        linked_list_t** list;
//} single_action_parameters;
///************************************************************************/
//
//void* perform_single_action(void* parameters)
//{
//        op_t* current_op = ((single_action_parameters*)parameters)->operations;
//        linked_list_t** current_list = ((single_action_parameters*)parameters)->list;
//        int* result;
//        switch (current_op->op)
//        {
//        case INSERT:
//                current_op->result = list_insert(current_list, current_op->index, current_op->data);
//                break;
//        case REMOVE:
//                current_op->result = list_remove(current_list, current_op->index);
//                break;
//        case CONTAINS:
//                current_op->result = list_contains(current_list, current_op->index);
//                break;
//        case UPDATE:
//                current_op->result = list_update_node(current_list, current_op->index, current_op->data);
//                break;
//        case COMPUTE:
//                result = &(current_op->result);
//                int function_result = list_node_compute(current_list, current_op->index,
//                                current_op->compute_func, (void*)(&result));
//                if (function_result != 0)
//                {
//                        current_op->result = function_result;
//                }
//                break;
//        }
//        return NULL;
//}
///************************************************************************/
//void list_batch(linked_list_t** list, int num_ops, op_t* ops)
//{
//        NULL_CHECK(list) {
//                return;
//        }
//        NULL_CHECK(*list) {
//                return;
//        }
//        NULL_CHECK(ops) {
//                return;
//        }
//        if (num_ops <= 0)
//        {
//                return;
//        }
//        single_action_parameters *parametersArray= malloc(num_ops*sizeof(single_action_parameters));
//        NULL_CHECK(parametersArray)
//        {
//                return;
//        }
//        pthread_t *threads= malloc(num_ops*sizeof(pthread_t));
//        NULL_CHECK(threads)
//        {
//                free(parametersArray);
//                return;
//        }
//        int i=0;
//
//        // Create all the threads
//        for (i=0; i< num_ops; i++)
//        {
//                parametersArray[i].operations = &ops[i];
//                parametersArray[i].list = list;
//                int result = pthread_create(&threads[i], NULL, perform_single_action, &(parametersArray[i]));
//                if (result != 0)
//                {
//                        // Failed creating a thread
//                        return;
//                }
//        }
//
//        // Wait for all the threads to finish
//        for (i=0; i< num_ops; i++)
//        {
//                pthread_join(threads[i], NULL);
//        }
//
//        free(threads);
//        free(parametersArray);
//}
//
///*
// * Alon: Auxiliary test function
// * TODO - remove this before submission
// */
//void list_print(linked_list_t** list) {
//        linked_list_t *node = *list;
//        node = node->next;
//        while (node != NULL) {
//                printf("\nIndex: %d\n", node->index);
//                node = node->next;
//        }
//}
//
//
//
